#pragma once
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<cstring>
#include<cstdio>
#include<functional>
namespace ThreadModlue{
    static uint32_t number=1;
    template<typename T>
    class Thread{
        using func_t =std::function<void(T)>;
        private:
           void EnableDetach(){
                _isdetach=true;
            }
        public:
            Thread(func_t func,const T& t):tid(0)
                                ,_isdetach(false)
                                ,isrunning(false)
                                ,_func(func)
                                ,_data(t){
                _name="Thread"+std::to_string(number++);
            }
            void Detach(){
                if(!_isdetach){
                    if(isrunning)
                    pthread_detach(tid);
                    EnableDetach();
                }
                else return;
            }
            void EnableRunning(){
                isrunning=true;
            }
            static void *Routine(void *args){
                 Thread<T>* self = static_cast<Thread<T>*>(args);
                  if(self->_isdetach)
                    //分离
                self->Detach();
                self->_func(self->_data);//回调函数
                return nullptr;
            }
            void Start(){
                if(isrunning)return;
                int n=pthread_create(&tid,nullptr,Routine,this);
                if(n>0){
                    std::cerr<<"Thread create failed "<<strerror(n)<<std::endl;
                    return;
                }
                 EnableRunning();
            }
            
            void Stop(){
                if(isrunning){
                    int n=pthread_cancel(tid);
                    if(n>0){
                        std::cerr<<"Thread cancel failed "<<strerror(n)<<std::endl;
                    }
                    else{
                       isrunning=false;
                       std::cout<<_name<<" stopped"<<std::endl;
                    }
                }
            }
            void Join(){
                if(_isdetach){
                    std::cerr<<"Thread is detached, can't join"<<std::endl;
                    return;
                }
                    int n=pthread_join(tid,&res);
                    if(n>0){
                        std::cerr<<"Thread join failed "<<strerror(n)<<std::endl;
                    }
            }
            std::string GetName(){
                return _name;
            }
            ~Thread(){
                if(tid!=0){
                    Stop();
                }
            }
        private:
            pthread_t tid;
            std::string _name;
            bool _isdetach;
            bool isrunning;
            void*res;
            func_t _func;
            T _data;
    };
}